package org.hawk.gwt.ppc.reflect.lang;

import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;

import junit.framework.TestCase;

import org.hawk.gwt.ppc.reflect.emul.java.lang.reflect.Field;
import org.hawk.gwt.ppc.reflect.lang.mock.Mock3;

public class FieldTestCase extends TestCase {
	private static final long MOCK3_SERIALVERSIONUID = Mock3.serialVersionUID;

	protected void setUp() throws Exception {
		ReflectionTestHelper.initialize();
	}
	
	private ClassDelegate<Mock3> getMock(){
		return ClassDelegate.forClass(Mock3.class);
	}
	
	public void testGetFields(){
		assertEquals(2, getMock().getFields().length);
		Set<String> names = new HashSet<String>();
		for(Field fld : getMock().getFields()){
			assertTrue(Modifier.isPublic(fld.getModifiers()));
			assertTrue(Modifier.isStatic(fld.getModifiers()));
			names.add(fld.getName());
		}
		assertTrue(names.contains("serialVersionUID"));
		assertTrue(names.contains("MOD"));
	}
	
	public void testGetField() throws SecurityException, NoSuchFieldException{
		Field fld = getMock().getField("MOD");
		assertTrue(Modifier.isPublic(fld.getModifiers()));
		assertTrue(Modifier.isStatic(fld.getModifiers()));
		assertEquals("MOD", fld.getName());
		assertEquals(int.class, fld.getType());
		try{
			getMock().getField("unknown");
			fail();
		}
		catch(NoSuchFieldException ex){}
		try{
			getMock().getField("");
			fail();
		}
		catch(NoSuchFieldException ex){}
		try{
			getMock().getField("parent");
			fail();
		}
		catch(NoSuchFieldException ex){}
		try{
			getMock().getField(null);
			fail();
		}
		catch(NullPointerException ex){}
	}
	
	public void testGetDeclaredFields(){
		assertEquals(3, getMock().getDeclaredFields().length);
		Set<String> names = new HashSet<String>();
		for(Field fld : getMock().getDeclaredFields()){
			if(fld.getName().equals("serialVersionUID")){
				assertTrue(Modifier.isPublic(fld.getModifiers()));
				assertTrue(Modifier.isStatic(fld.getModifiers()));
			}
			else {
				assertTrue(Modifier.isPrivate(fld.getModifiers()));
			}
			if(fld.getName().equals("name")){
				assertTrue(Modifier.isVolatile(fld.getModifiers()));
			}
			names.add(fld.getName());
		}
		assertTrue(names.contains("serialVersionUID"));
		assertTrue(names.contains("name"));
		assertTrue(names.contains("parent"));
	}
	
	public void testGetDeclaredField() throws SecurityException, NoSuchFieldException{
		Field fld = getMock().getField("serialVersionUID");
		assertTrue(Modifier.isPublic(fld.getModifiers()));
		assertTrue(Modifier.isStatic(fld.getModifiers()));
		assertEquals("serialVersionUID", fld.getName());
		assertEquals(long.class, fld.getType());
		try{
			getMock().getField("unknown");
			fail();
		}
		catch(NoSuchFieldException ex){}
		try{
			getMock().getField("");
			fail();
		}
		catch(NoSuchFieldException ex){}
		fld = getMock().getDeclaredField("parent");
		assertTrue(Modifier.isPrivate(fld.getModifiers()));
		assertEquals("parent", fld.getName());
		assertEquals(Mock3.class, fld.getType());
		try{
			getMock().getField(null);
			fail();
		}
		catch(NullPointerException ex){}
	}
	
	public void testGet() throws Exception {
		Field fld = getMock().getField("serialVersionUID");
		assertEquals(MOCK3_SERIALVERSIONUID, fld.getLong(null));
		Mock3 obj = new Mock3();
		fld = getMock().getDeclaredField("name");
		try{
			assertEquals("?", fld.get(obj));
			fail();
		}
		catch(IllegalAccessException ex){}
		fld.setAccessible(true);
		assertEquals("?", fld.get(obj));
	}
	
	public void testSet() throws Exception {
		Field fld = getMock().getField("serialVersionUID");
		try{
			fld.set(null, 5L);
			fail();
		}
		catch(IllegalAccessException ex){}
		fld.setAccessible(true);
		try{
			fld.set(null, 5L);
			fail();
		}
		catch(IllegalAccessException ex){}
		assertEquals(MOCK3_SERIALVERSIONUID, fld.getLong(null));
		Mock3 obj = new Mock3();
		fld = getMock().getDeclaredField("name");
		assertEquals("?", obj.getName());
		try{
			fld.set(obj, "zzz");
			fail();
		}
		catch(IllegalAccessException ex){}
		assertEquals("?", obj.getName());
		fld.setAccessible(true);
		fld.set(obj, "zzz");
		assertEquals("zzz", obj.getName());
	}
}
